package cn.bellychang.wangzheng.queue.loop;

import cn.bellychang.bobo.queue.Queue;

/**
 * @author ChangLiang
 * @date 2021/1/28
 */
public class CircularQueue<E> implements Queue<E> {

    private E[] items;

    private int head;

    private int tail;

    private int count;

    private int capacity;

    private static final int EXTEND_FACTOR = 2;

    public CircularQueue(int capacity) {
        items = (E[]) new Object[capacity];
        this.capacity = capacity;
    }

    @Override
    public int getSize() {
        return count;
    }

    @Override
    public boolean isEmpty() {
        return count == 0;
    }

    @Override
    public void enqueue(E e) {
        if (count == capacity) {
            // 有界
            E[] newItems = (E[]) new Object[capacity * EXTEND_FACTOR];
            System.arraycopy(items, head, newItems, 0, count);
            items = newItems;
            this.capacity = capacity * EXTEND_FACTOR;
            head = 0;
            tail = count;

            // 无界
//            throw new RuntimeException("queue is full");
        }
        items[tail++] = e;
        if (tail == capacity) {
            tail = 0;
        }
        count++;
    }

    @Override
    public E dequeue() {
        if (count == 0) {
            throw new RuntimeException("queue is empty");
        }
        E temp = items[head++];
        if (head == capacity) {
            head = 0;
        }
        count--;
        return temp;
    }

    @Override
    public E getFront() {
        if (count == 0) {
            throw new RuntimeException("queue is empty");
        }
        return items[head];
    }

    public int getHead() {
        return this.head;
    }

    public int getTail() {
        return this.tail;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Queue Tail {");
        E[] arr = (E[]) new Object[count];
        int index = count-1;

        for (int i = head; i < head + count; i++) {
            arr[index--] = items[i % capacity];
        }

        for (E e : arr) {
            builder.append(e).append("->");
        }

        return builder.toString().endsWith("->") ?
                builder.substring(0, builder.length() - 2) + "} Head" :
                builder.append("} Head").toString();
    }
}
